home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / remin301.zip / REMIN300.ZIP / EXPR.C < prev    next >
C/C++ Source or Header  |  1992-11-10  |  37KB  |  1,213 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  EXPR.C                                                     */
  4. /*                                                             */
  5. /*  This file contains routines to parse and evaluate          */
  6. /*  expressions.                                               */
  7. /*                                                             */
  8. /*  Copyright 1991 by David F. Skoll.                          */
  9. /*                                                             */
  10. /***************************************************************/
  11.  
  12. /* If we're using Turbo C, turn off annoying warning messages! */
  13. #ifdef __TURBOC__
  14. #pragma warn -pia
  15. #endif
  16.  
  17. #include <stdio.h>
  18. #include <ctype.h>
  19. #include <string.h>
  20. #include "config.h"
  21. #ifdef HAVE_STDLIB_H
  22. #include <stdlib.h>
  23. #endif
  24. #ifdef HAVE_MALLOC_H
  25. #include <malloc.h>
  26. #endif
  27. #include "err.h"
  28. #include "types.h"
  29. #include "expr.h"
  30. #include "protos.h"
  31. #include "globals.h"
  32.  
  33. #define ISID(c) (isalnum(c) || (c) == '_')
  34. #define EQ 0
  35. #define GT 1
  36. #define LT 2
  37. #define GE 3
  38. #define LE 4
  39. #define NE 5
  40.  
  41. static char ExprBuf[TOKSIZE+1];
  42. static char CoerceBuf[TOKSIZE+1];
  43. extern int NumFuncs;
  44.  
  45. #ifdef HAVE_PROTOS
  46. PRIVATE int Multiply(void), Divide(void), Mod(void), Add(void),
  47.        Subtract(void), GreaterThan(void), LessThan(void),
  48.        EqualTo(void), NotEqual(void), LessOrEqual(void),
  49.        GreaterOrEqual(void), LogAND(void), LogOR(void),
  50.        UnMinus(void), LogNot(void),
  51.        Compare(int);
  52. PRIVATE Operator *FindFunc(char *name, Operator where[], int num);
  53. #else
  54. PRIVATE int Multiply(), Divide(), Mod(), Add(),
  55.        Subtract(), GreaterThan(), LessThan(),
  56.        EqualTo(), NotEqual(), LessOrEqual(),
  57.        GreaterOrEqual(), LogAND(), LogOR(),
  58.            UnMinus(), LogNot(), Compare();
  59. PRIVATE Operator *FindFunc();
  60. #endif
  61.  
  62. PRIVATE int MakeValue ARGS ((char *s, Value *v, Var *locals));
  63. PRIVATE int PushOpStack ARGS ((Operator *op));
  64. PRIVATE int PopOpStack ARGS ((Operator *op));
  65.  
  66. /* Binary operators - all left-associative */
  67.  
  68. /* Make SURE they are sorted lexically... this may die on an EBCDIC
  69.    system... */
  70.  
  71. Operator BinOp[] = {
  72.    { "!=", 15, BIN_OP, NotEqual },
  73.    { "%", 20, BIN_OP, Mod },
  74.    { "&&", 14, BIN_OP, LogAND },
  75.    { "*", 20, BIN_OP, Multiply },
  76.    { "+", 18, BIN_OP, Add },
  77.    { "-", 18, BIN_OP, Subtract },
  78.    { "/", 20, BIN_OP, Divide },
  79.    { "<", 16, BIN_OP, LessThan },
  80.    { "<=", 16, BIN_OP, LessOrEqual },
  81.    { "==", 15, BIN_OP, EqualTo },
  82.    { ">", 16, BIN_OP, GreaterThan },
  83.    { ">=", 16, BIN_OP, GreaterOrEqual },
  84.    { "||", 12, BIN_OP, LogOR },
  85. };
  86. #define NUM_BIN_OPS (sizeof(BinOp) / sizeof(Operator))
  87.  
  88. /* These ones must be sorted too. */
  89. Operator UnOp[] = {
  90.    { "!", 22, UN_OP, LogNot },
  91.    { "-", 22, UN_OP, UnMinus },
  92. };
  93. #define NUM_UN_OPS (sizeof(UnOp) / sizeof(Operator))
  94.  
  95. /* Functions have the same definitions as operators, except the prec field
  96.    is used to indicate how many arguments are needed. */
  97. extern Operator Func[];
  98.  
  99. Operator OpStack[OP_STACK_SIZE];
  100. Value    ValStack[VAL_STACK_SIZE];
  101. int OpStackPtr, ValStackPtr;
  102.  
  103. /***************************************************************/
  104. /*                                                             */
  105. /*  DebugPerform                                               */
  106. /*                                                             */
  107. /*  Execute an operator or function with debugging.            */
  108. /*                                                             */
  109. /***************************************************************/
  110. #ifdef HAVE_PROTOS
  111. PRIVATE int DebugPerform(Operator *op)
  112. #else
  113. static int DebugPerform(op)
  114. Operator *op;
  115. #endif
  116. {
  117.    int r;
  118.  
  119.    if (op->type == UN_OP) {
  120.       fprintf(ErrFp, "%s ", op->name);
  121.       PrintValue(&ValStack[ValStackPtr-1], ErrFp);
  122.    } else { /* Must be binary operator */
  123.       PrintValue(&ValStack[ValStackPtr-2], ErrFp);
  124.       fprintf(ErrFp, " %s ", op->name);
  125.       PrintValue(&ValStack[ValStackPtr-1], ErrFp);
  126.    }
  127.  
  128.    r = (op->func)();
  129.    fprintf(ErrFp, " => ");
  130.    if (!r) {
  131.       PrintValue(&ValStack[ValStackPtr-1], ErrFp);
  132.       putc('\n', ErrFp);
  133.    } else {
  134.       fprintf(ErrFp, "%s\n", ErrMsg[r]);
  135.    }
  136.    return r;
  137. }
  138.  
  139. /***************************************************************/
  140. /*                                                             */
  141. /*  CleanStack                                                 */
  142. /*                                                             */
  143. /*  Clean the stack after an error occurs.                     */
  144. /*                                                             */
  145. /***************************************************************/
  146. #ifdef HAVE_PROTOS
  147. PRIVATE void CleanStack(void)
  148. #else
  149. static void CleanStack()
  150. #endif
  151. {
  152.    int i;
  153.  
  154.    for (i=0; i<ValStackPtr; i++) DestroyValue(&ValStack[i]);
  155.    ValStackPtr = 0;
  156. }
  157.  
  158. /***************************************************************/
  159. /*                                                             */
  160. /*  PeekChar - peek ahead to next char.                        */
  161. /*                                                             */
  162. /***************************************************************/
  163. #ifdef HAVE_PROTOS
  164. PRIVATE char PeekChar(char **s)
  165. #else
  166. static char PeekChar(s)
  167. char **s;
  168. #endif
  169. {
  170.    char *t = *s;
  171.    while (*t && isspace(*t)) t++;
  172.    return *t;
  173. }
  174.  
  175. /***************************************************************/
  176. /*                                                             */
  177. /*  ParseExprToken                                             */
  178. /*                                                             */
  179. /*  Read a token.                                              */
  180. /*                                                             */
  181. /***************************************************************/
  182. #ifdef HAVE_PROTOS
  183. PRIVATE int ParseExprToken(char *out, char **in)
  184. #else
  185. static int ParseExprToken(out, in)
  186. char *out;
  187. char **in;
  188. #endif
  189. {
  190.  
  191.    char c;
  192.    
  193.    *out = 0;
  194. /* Skip white space */
  195.    while (**in && isspace(**in)) (*in)++;
  196.    
  197.    if (!**in) return OK;
  198.  
  199.    *out++ = c = *(*in)++;
  200.    *out = 0;
  201.  
  202.    switch(c) {
  203.       case COMMA:
  204.       case END_OF_EXPR:
  205.       case '+':
  206.       case '-':
  207.       case '*':
  208.       case '/':
  209.       case '(':
  210.       case ')':
  211.       case '%': return OK;
  212.  
  213.       case '&':
  214.       case '|':
  215.       case '=': if (**in == c) {
  216.                 *out++ = c;
  217.                 *out = 0;
  218.                 (*in)++;
  219.            }
  220.              return OK;
  221.              
  222.       case '!':
  223.       case '>':
  224.       case '<': if (**in == '=') {
  225.                 *out++ = '=';
  226.                 *out = 0;
  227.                 (*in)++;
  228.            }
  229.            return OK;
  230.    }           
  231.  
  232.    /* Handle the parsing of quoted strings */
  233.    if (c == '\"') {
  234.       while (**in) if ((c = *out++ = *(*in)++) == '\"') break;
  235.       *out = 0;
  236.       if (c == '\"') return OK ; else return E_MISS_QUOTE;
  237.    }
  238.  
  239.    if (!ISID(c)) return E_ILLEGAL_CHAR;
  240.  
  241.    /* Parse a constant, variable name or function */
  242.    while (ISID(**in) || **in == ':') *out++ = *(*in)++;
  243.  
  244.    /* Chew up any remaining white space */
  245.    while (**in && isspace(**in)) (*in)++;
  246.  
  247.    /* Peek ahead - is it '('?  Then we have a function call */
  248.    if (**in == '(') *out++ = *(*in)++;
  249.  
  250.    *out = 0;
  251.    return OK;
  252. }
  253.  
  254. /***************************************************************/
  255. /*                                                             */
  256. /*  EvalExpr                                                   */
  257. /*  Evaluate an expression.  Return 0 if OK, non-zero if error */
  258. /*  Put the result into value pointed to by v.                 */
  259. /*                                                             */
  260. /***************************************************************/
  261. #ifdef HaveProtos
  262. PUBLIC int EvalExpr(char **e, Value *v)
  263. #else
  264. int EvalExpr(e, v)
  265. char **e;
  266. Value *v;
  267. #endif
  268. {
  269.    int r;
  270.  
  271.    OpStackPtr = 0;
  272.    ValStackPtr = 0;
  273.    r = Evaluate(e, NULL);
  274.  
  275.    /* Put last character parsed back onto input stream */
  276.    if (*ExprBuf) (*e)--;
  277.  
  278.    if (r) {
  279.       CleanStack();
  280.       return r;
  281.    }
  282.    r = CopyValue(v, ValStack);
  283.    DestroyValue(ValStack);
  284.    return r;
  285. }
  286.  
  287. /* Evaluate - do the actual work of evaluation. */
  288. #ifdef HAVE_PROTOS
  289. PUBLIC int Evaluate(char **s, Var *locals)
  290. #else
  291. int Evaluate(s, locals)
  292. char **s;
  293. Var *locals;
  294. #endif
  295. {
  296.    int OpBase, ValBase;
  297.    int r;
  298.    Operator *f;
  299.    int args; /* Number of function arguments */
  300.    Operator op, op2;
  301.    Value va;
  302.    char *ufname;
  303.    
  304.    OpBase = OpStackPtr;
  305.    ValBase = ValStackPtr;
  306.    
  307.    while(1) {
  308. /* Looking for a value.  Accept: value, unary op, func. call or left paren */
  309.       r = ParseExprToken(ExprBuf, s);
  310.       if (r) return r;
  311.       if (!*ExprBuf) return E_EOLN;
  312.  
  313.       if (*ExprBuf == '(') { /* Parenthesized expression */
  314.      r = Evaluate(s, locals);  /* Leaves the last parsed token in ExprBuf */
  315.          if (r) return r;
  316.      if (*ExprBuf != ')') return E_MISS_RIGHT_PAREN;
  317.       } else if (*ExprBuf == '+') continue; /* Ignore unary + */
  318.       else if (*(ExprBuf + strlen(ExprBuf) -1) == '(') { /* Function Call */
  319.      *(ExprBuf + strlen(ExprBuf) - 1) = 0;
  320.      f = FindFunc(ExprBuf, Func, NumFuncs);
  321.      if (!f) {
  322.         ufname = StrDup(ExprBuf);
  323.         if (!ufname) return E_NO_MEM;
  324.      }
  325.      args = 0;
  326.      if (PeekChar(s) == ')') { /* Function has no arguments */
  327.         if (f) r = CallFunc(f, 0);
  328.         else {
  329.            r = CallUserFunc(ufname, 0);
  330.            free(ufname);
  331.         }
  332.         if (r) return r;
  333.         (void) ParseExprToken(ExprBuf, s); /* Guaranteed to be right paren. */
  334.      } else { /* Function has some arguments */
  335.         while(1) {
  336.            args++;
  337.            r = Evaluate(s, locals);
  338.            if (r) return r;
  339.            if (*ExprBuf == ')') break;
  340.            else if (*ExprBuf != ',') return E_ILLEGAL_CHAR;
  341.             }
  342.         if (f) r = CallFunc(f, args);
  343.         else {
  344.            r = CallUserFunc(ufname, args);
  345.            free(ufname);
  346.         }
  347.         if (r) return r;
  348.          }
  349.       } else { /* Unary operator */
  350.      f = FindFunc(ExprBuf, UnOp, NUM_UN_OPS);
  351.          if (f) {
  352.             r = PushOpStack(f);
  353.             if (r) return r;
  354.         continue;  /* Still looking for an atomic vlue */
  355.      } else if (!ISID(*ExprBuf) && *ExprBuf != '"') {
  356.         return E_ILLEGAL_CHAR;
  357.      } else { /* Must be a literal value */
  358.         r = MakeValue(ExprBuf, &va, locals);
  359.         if (r) return r;
  360.         r = PushValStack(&va);
  361.         if (r) return r;
  362.      }
  363.       }
  364. /* OK, we've got a literal value; now, we're looking for the end of the
  365.       expression, or a binary operator. */
  366.       r = ParseExprToken(ExprBuf, s);
  367.       if (r) return r;
  368.       if (*ExprBuf == 0 || *ExprBuf == ',' || *ExprBuf == ']' || *ExprBuf == ')') {
  369.    /* We've hit the end of the expression.  Pop off and evaluate until
  370.          OpStackPtr = OpBase and ValStackPtr = ValBase+1 */
  371.          while (OpStackPtr > OpBase) {
  372.             r = PopOpStack(&op);
  373.             if (r) return r;
  374.         if (DebugFlag & DB_PRTEXPR)
  375.            r=DebugPerform(&op);
  376.         else
  377.            r=(op.func)();
  378.           if (r) {
  379.            Eprint("Operator '%s' %s", op.name, ErrMsg[r]);
  380.            return r;
  381.             }
  382.      }
  383.          if (ValStackPtr != ValBase+1) return E_STACK_ERR; else return OK;
  384.       }
  385.       /* Must be a binary operator */
  386.       f = FindFunc(ExprBuf, BinOp, NUM_BIN_OPS);
  387.       if (!f) return E_EXPECTING_BINOP;
  388.  
  389.       /* While operators of higher or equal precedence are on the stack,
  390.          pop them off and evaluate */
  391.       while (OpStackPtr > OpBase && OpStack[OpStackPtr-1].prec >= f->prec) {
  392.          r = PopOpStack(&op2);
  393.          if (r) return r;
  394.      if (DebugFlag & DB_PRTEXPR)
  395.         r=DebugPerform(&op2);
  396.      else
  397.         r=(op2.func)();
  398.      if (r) {
  399.         Eprint("Operator '%s' %s", op2.name, ErrMsg[r]);
  400.         return r;
  401.          }
  402.       }
  403.       r = PushOpStack(f);
  404.       if (r) return r;
  405.    }
  406. }
  407.    
  408. /***************************************************************/
  409. /*                                                             */
  410. /*  MakeValue                                                  */
  411. /*  Generate a literal value.  It's either a string, a number  */
  412. /*  or the value of a symbol.                                  */
  413. /*                                                             */
  414. /***************************************************************/
  415. #ifdef HAVE_PROTOS
  416. PRIVATE int MakeValue(char *s, Value *v, Var *locals)
  417. #else
  418. static int MakeValue(s, v, locals)
  419. char *s;
  420. Value *v;
  421. Var *locals;
  422. #endif
  423. {
  424.    int len;
  425.    int h, m, r;
  426.  
  427.    if (*s == '\"') { /* It's a literal string */
  428.       len = strlen(s)-1;
  429.       v->type = STR_TYPE;
  430.       v->v.str = (char *) malloc(len);
  431.       if (! v->v.str) {
  432.          v->type = ERR_TYPE;
  433.          return E_NO_MEM;
  434.       }
  435.       strncpy(v->v.str, s+1, len-1);
  436.       *(v->v.str+len-1) = 0;
  437.       return OK;
  438.    } else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
  439.       len = 0;
  440.       while (*s && isdigit(*s)) {
  441.          len *= 10;
  442.          len += (*s++ - '0');
  443.       }
  444.       if (*s == ':') { /* Must be a literal time */
  445.      s++;
  446.      if (!isdigit(*s)) return E_BAD_TIME;
  447.      h = len;
  448.      m = 0;
  449.      while (isdigit(*s)) {
  450.         m *= 10;
  451.         m += *s - '0';
  452.         s++;
  453.      }
  454.      if (*s || h>23 || m>59) return E_BAD_TIME;
  455.      v->type = TIM_TYPE;
  456.      v->v.val = h*60 + m;
  457.      return OK;
  458.       }
  459.       /* Not a time - must be a number */
  460.       if (*s) return E_BAD_NUMBER;
  461.       v->type = INT_TYPE;
  462.       v->v.val = len;
  463.       return OK;
  464.    } else /* Must be a symbol */
  465.      if (DebugFlag & DB_PRTEXPR)
  466.         fprintf(ErrFp, "%s => ", s);
  467.      r = GetVarValue(s, v, locals);
  468.      if (! (DebugFlag & DB_PRTEXPR)) return r;
  469.      if (r == OK) {
  470.         PrintValue(v, ErrFp);
  471.     putc('\n', ErrFp);
  472.      }
  473.      return r;
  474. }
  475.  
  476. /***************************************************************/
  477. /*                                                             */
  478. /*  PushOpStack                                                */
  479. /*                                                             */
  480. /*  Push an operator onto the operator stack.                  */
  481. /*                                                             */
  482. /***************************************************************/
  483. #ifdef HAVE_PROTOS
  484. PRIVATE int PushOpStack(Operator *op)
  485. #else
  486. static int PushOpStack(op)
  487. Operator *op;
  488. #endif
  489. {
  490.    if (OpStackPtr >= OP_STACK_SIZE)
  491.       return E_OP_STK_OVER;
  492.    else {
  493.       OpStack[OpStackPtr++] = *op;
  494.       return OK;
  495.    }
  496. }
  497.  
  498. /***************************************************************/
  499. /*                                                             */
  500. /*  PushValStack                                               */
  501. /*                                                             */
  502. /*  Push a value onto the value stack.                         */
  503. /*                                                             */
  504. /***************************************************************/
  505. #ifdef HAVE_PROTOS
  506. PUBLIC int PushValStack(Value *val)
  507. #else
  508. int PushValStack(val)
  509. Value *val;
  510. #endif
  511. {
  512.    if (ValStackPtr >= VAL_STACK_SIZE)
  513.       return E_VA_STK_OVER;
  514.    else {
  515.       ValStack[ValStackPtr++] = *val;
  516.       return OK;
  517.    }
  518. }
  519.  
  520. /***************************************************************/
  521. /*                                                             */
  522. /*  PopOpStack                                                 */
  523. /*                                                             */
  524. /*  Pop an operator from the operator stack.                   */
  525. /*                                                             */
  526. /***************************************************************/
  527. #ifdef HAVE_PROTOS
  528. PRIVATE int PopOpStack(Operator *op)
  529. #else
  530. static int PopOpStack(op)
  531. Operator *op;
  532. #endif
  533. {
  534.    if (OpStackPtr <= 0)
  535.       return E_OP_STK_UNDER;
  536.    else {
  537.       *op = OpStack[--OpStackPtr];
  538.       return OK;
  539.    }
  540. }
  541.  
  542. /***************************************************************/
  543. /*                                                             */
  544. /*  PopValStack                                               */
  545. /*                                                             */
  546. /*  Pop a value onto the value stack.                         */
  547. /*                                                             */
  548. /***************************************************************/
  549. #ifdef HAVE_PROTOS
  550. PUBLIC int PopValStack(Value *val)
  551. #else
  552. int PopValStack(val)
  553. Value *val;
  554. #endif
  555. {
  556.    if (ValStackPtr <= 0)
  557.       return E_VA_STK_UNDER;
  558.    else {
  559.       *val = ValStack[--ValStackPtr];
  560.       return OK;
  561.    }
  562. }
  563.  
  564. /***************************************************************/
  565. /*                                                             */
  566. /*  DoCoerce - actually coerce a value to the specified type.  */
  567. /*                                                             */
  568. /***************************************************************/
  569. #ifdef HAVE_PROTOS
  570. PUBLIC int DoCoerce(char type, Value *v)
  571. #else
  572. int DoCoerce(type, v)
  573. char type;
  574. Value *v;
  575. #endif
  576. {
  577.    int h, d, m, y, i;
  578.    char *s;
  579.    
  580.    /* Do nothing if value is already the right type */
  581.    if (type == v->type) return OK;
  582.    
  583.    switch(type) {
  584.       case STR_TYPE:
  585.          switch(v->type) {
  586.             case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break;
  587.             case TIM_TYPE: sprintf(CoerceBuf, "%02d:%02d", v->v.val / 60, v->v.val % 60);
  588.                break;
  589.         case DATE_TYPE: FromJulian(v->v.val, &y, &m, &d);
  590.                 sprintf(CoerceBuf, "%04d/%02d/%02d", y, m+1, d);
  591.                 break;
  592.             default: return E_CANT_COERCE;
  593.          }
  594.          v->type = STR_TYPE;
  595.      v->v.str = StrDup(CoerceBuf);
  596.      if (!v->v.str) {
  597.         v->type = ERR_TYPE;
  598.         return E_NO_MEM;
  599.      }
  600.      return OK;
  601.  
  602.       case INT_TYPE:
  603.      i = 0;
  604.      m = 1;
  605.      switch(v->type) {
  606.         case STR_TYPE:
  607.            s = v->v.str;
  608.            if (*s == '-') {
  609.           m = -1;
  610.           s++;
  611.            }
  612.            while(*s && isdigit(*s)) {
  613.                   i *= 10;
  614.                   i += (*s++) - '0';
  615.                }
  616.                if (*s) {
  617.           free (v->v.str);
  618.                   v->type = ERR_TYPE;
  619.                   return E_CANT_COERCE;
  620.                }
  621.                free(v->v.str);
  622.                v->type = INT_TYPE;
  623.            v->v.val = i * m;
  624.            return OK;
  625.  
  626.         case DATE_TYPE:
  627.         case TIM_TYPE:
  628.            v->type = INT_TYPE;
  629.            return OK;
  630.  
  631.             default: return E_CANT_COERCE;
  632.      }
  633.  
  634.       case DATE_TYPE:
  635.      switch(v->type) {
  636.         case INT_TYPE:
  637.            if(v->v.val >= 0) {
  638.           v->type = DATE_TYPE;
  639.           return OK;
  640.            } else return E_2LOW;
  641.  
  642.         case STR_TYPE:
  643.            y=0; m=0; d=0;
  644.            s = v->v.str;
  645.            if (!isdigit(*s)) return E_CANT_COERCE;
  646.            while (isdigit(*s)) {
  647.           y *= 10;
  648.           y += *s++ - '0';
  649.            }
  650.            if (*s++ != '/') return E_CANT_COERCE;
  651.            if (!isdigit(*s)) return E_CANT_COERCE;
  652.            while (isdigit(*s)) {
  653.           m *= 10;
  654.           m += *s++ - '0';
  655.            }
  656.            m--;
  657.            if (*s++ != '/') return E_CANT_COERCE;
  658.            if (!isdigit(*s)) return E_CANT_COERCE;
  659.            while (isdigit(*s)) {
  660.           d *= 10;
  661.           d += *s++ - '0';
  662.            }
  663.            if (*s || y < BASE || y > BASE+YR_RANGE ||
  664.             m>11 || d<1 || d>DaysInMonth(m, y)) return E_CANT_COERCE;
  665.            v->type = DATE_TYPE;
  666.            free(v->v.str);
  667.            v->v.val = Julian(y, m, d);
  668.            return OK;
  669.  
  670.         default: return E_CANT_COERCE;
  671.      }
  672.  
  673.       case TIM_TYPE:
  674.      switch(v->type) {
  675.         case INT_TYPE:
  676.            v->type = TIM_TYPE;
  677.            v->v.val %= 1440;
  678.            if (v->v.val < 0) v->v.val += 1440;
  679.            return OK;
  680.  
  681.         case STR_TYPE:
  682.            h = 0;
  683.            m = 0;
  684.            s = v->v.str;
  685.            if (!isdigit(*s)) return E_CANT_COERCE;
  686.            while (isdigit(*s)) {
  687.           h *= 10;
  688.           h += *s++ - '0';
  689.            }
  690.            if (*s++ != ':') return E_CANT_COERCE;
  691.            if (!isdigit(*s)) return E_CANT_COERCE;
  692.            while (isdigit(*s)) {
  693.           m *= 10;
  694.           m += *s++ - '0';
  695.            }
  696.            if (*s || h>23 || m>59) return E_CANT_COERCE;
  697.            v->type = TIM_TYPE;
  698.            free(v->v.str);
  699.            v->v.val = h*60+m;
  700.            return OK;
  701.  
  702.         default: return E_CANT_COERCE;
  703.      }
  704.       default: return E_CANT_COERCE;
  705.    }
  706. }
  707.  
  708. /***************************************************************/
  709. /*                                                             */
  710. /*  DestroyValue                                               */
  711. /*                                                             */
  712. /*  If value is of type string, deallocate string memory.      */
  713. /*                                                             */
  714. /***************************************************************/
  715. #ifdef HAVE_PROTOS
  716. PUBLIC void DestroyValue(Value *v)
  717. #else
  718. void DestroyValue(v)
  719. Value *v;
  720. #endif
  721. {
  722.    if (v->type == STR_TYPE && v->v.str) free(v->v.str);
  723.    v->type = ERR_TYPE;
  724. }
  725.  
  726. /***************************************************************/
  727. /*                                                             */
  728. /*  Add                                                        */
  729. /*                                                             */
  730. /*  Perform addition.                                          */
  731. /*                                                             */
  732. /***************************************************************/
  733. #ifdef HAVE_PROTOS
  734. PRIVATE int Add(void)
  735. #else
  736. static int Add()
  737. #endif
  738. {
  739.    Value v1, v2, v3;
  740.    int r;
  741.    
  742.    if (r = PopValStack(&v2)) return r;
  743.    if (r = PopValStack(&v1)) {
  744.       DestroyValue(&v2);
  745.       return r;
  746.    }
  747.    
  748. /* If both are ints, just add 'em */
  749.    if (v2.type == INT_TYPE && v1.type == INT_TYPE) {
  750.       v2.v.val += v1.v.val;
  751.       return (PushValStack(&v2));
  752.    }
  753.  
  754. /* If it's a date plus an int, add 'em */
  755.    if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) ||
  756.        (v1.type == INT_TYPE && v2.type == DATE_TYPE)) {
  757.       v1.v.val += v2.v.val;
  758.       v1.type = DATE_TYPE;
  759.       return PushValStack(&v1);
  760.    }
  761.    
  762. /* If it's a time plus an int, add 'em mod 1440 */
  763.    if ((v1.type == TIM_TYPE && v2.type == INT_TYPE) ||
  764.        (v1.type == INT_TYPE && v2.type == TIM_TYPE)) {
  765.       v1.v.val = (v1.v.val + v2.v.val) % 1440;
  766.       v1.type = TIM_TYPE;
  767.       return PushValStack(&v1);
  768.    }       
  769.  
  770. /* If either is a string, coerce them both to strings and concatenate */
  771.    if (v1.type == STR_TYPE || v2.type == STR_TYPE) {
  772.       if (r = DoCoerce(STR_TYPE, &v1)) {
  773.            DestroyValue(&v1); DestroyValue(&v2);
  774.          return r;
  775.       }
  776.       if (r = DoCoerce(STR_TYPE, &v2)) {
  777.            DestroyValue(&v1); DestroyValue(&v2);
  778.            return r;
  779.       }
  780.       v3.type = STR_TYPE;
  781.       v3.v.str = (char *) malloc(strlen(v1.v.str) + strlen(v2.v.str) + 1);
  782.       if (!v3.v.str) {
  783.            DestroyValue(&v1); DestroyValue(&v2);
  784.      return E_NO_MEM;
  785.       }
  786.       strcpy(v3.v.str, v1.v.str);
  787.       strcat(v3.v.str, v2.v.str);
  788.       DestroyValue(&v1); DestroyValue(&v2);
  789.       return (PushValStack(&v3));
  790.    }
  791.  
  792.    /* Don't handle other types yet */
  793.    return E_BAD_TYPE;
  794. }
  795.       
  796. /***************************************************************/
  797. /*                                                             */
  798. /*  Subtract                                                   */
  799. /*                                                             */
  800. /*  Perform subtraction.                                       */
  801. /*                                                             */
  802. /***************************************************************/
  803. #ifdef HAVE_PROTOS
  804. PRIVATE int Subtract(void)
  805. #else
  806. static int Subtract()
  807. #endif
  808. {
  809.    Value v1, v2;
  810.    int r;
  811.    
  812.    if (r = PopValStack(&v2)) return r;
  813.    if (r = PopValStack(&v1)) {
  814.       DestroyValue(&v2);
  815.       return r;
  816.    }
  817.  
  818.    /* If they're both INTs, do subtraction */
  819.    if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
  820.       v1.v.val -= v2.v.val;
  821.       return PushValStack(&v1);
  822.    }
  823.  
  824.    /* If it's a date minus an int, do subtraction, checking for underflow */
  825.    if (v1.type == DATE_TYPE && v2.type == INT_TYPE) {
  826.       v1.v.val -= v2.v.val;
  827.       if (v1.v.val < 0) return E_DATE_OVER;
  828.       return PushValStack(&v1);
  829.    }
  830.  
  831.    /* If it's a time minus an int, do subtraction mod 1440 */
  832.    if (v1.type == TIM_TYPE && v2.type == INT_TYPE) {
  833.       v1.v.val = (v1.v.val - v2.v.val) % 1440;
  834.       return PushValStack(&v1);
  835.    }
  836.  
  837.    /* If it's a time minus a time or a date minus a date, do it */
  838.    if ((v1.type == TIM_TYPE && v2.type == TIM_TYPE) ||
  839.        (v1.type == DATE_TYPE && v2.type == DATE_TYPE)) {
  840.       v1.v.val -= v2.v.val;
  841.       v1.type = INT_TYPE;
  842.       return PushValStack(&v1);
  843.    }
  844.  
  845.    /* Must be types illegal for subtraction */
  846.    DestroyValue(&v1); DestroyValue(&v2);
  847.    return E_BAD_TYPE;
  848. }
  849.  
  850. /***************************************************************/
  851. /*                                                             */
  852. /*  Multiply                                                   */
  853. /*                                                             */
  854. /*  Perform multiplication.                                    */
  855. /*                                                             */
  856. /***************************************************************/
  857. #ifdef HAVE_PROTOS
  858. PRIVATE int Multiply(void)
  859. #else
  860. static int Multiply()
  861. #endif
  862. {
  863.    Value v1, v2;
  864.    int r;
  865.  
  866.    if (r = PopValStack(&v2)) return r;
  867.    if (r = PopValStack(&v1)) {
  868.       DestroyValue(&v2);
  869.       return r;
  870.    }
  871.  
  872.    if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
  873.       v1.v.val *= v2.v.val;
  874.       return PushValStack(&v1);
  875.    }
  876.    DestroyValue(&v1); DestroyValue(&v2);
  877.    return E_BAD_TYPE;
  878. }
  879.  
  880. /***************************************************************/
  881. /*                                                             */
  882. /*  Divide                                                     */
  883. /*                                                             */
  884. /*  Perform division.                                          */
  885. /*                                                             */
  886. /***************************************************************/
  887. #ifdef HAVE_PROTOS
  888. PRIVATE int Divide(void)
  889. #else
  890. static int Divide()
  891. #endif
  892. {
  893.    Value v1, v2;
  894.    int r;
  895.  
  896.    if (r = PopValStack(&v2)) return r;
  897.    if (r = PopValStack(&v1)) {
  898.       DestroyValue(&v2);
  899.       return r;
  900.    }
  901.  
  902.    if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
  903.       if (v2.v.val == 0) return E_DIV_ZERO;
  904.       v1.v.val /= v2.v.val;
  905.       return PushValStack(&v1);
  906.    }
  907.    DestroyValue(&v1); DestroyValue(&v2);
  908.    return E_BAD_TYPE;
  909. }
  910.  
  911. /***************************************************************/
  912. /*                                                             */
  913. /*  Mod                                                        */
  914. /*                                                             */
  915. /*  Perform modulus function.                                  */
  916. /*                                                             */
  917. /***************************************************************/
  918. #ifdef HAVE_PROTOS
  919. PRIVATE int Mod(void)
  920. #else
  921. static int Mod()
  922. #endif
  923. {
  924.    Value v1, v2;
  925.    int r;
  926.  
  927.    if (r = PopValStack(&v2)) return r;
  928.    if (r = PopValStack(&v1)) {
  929.       DestroyValue(&v2);
  930.       return r;
  931.    }
  932.  
  933.    if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
  934.       if (v2.v.val == 0) return E_DIV_ZERO;
  935.       v1.v.val %= v2.v.val;
  936.       return PushValStack(&v1);
  937.    }
  938.    DestroyValue(&v1); DestroyValue(&v2);
  939.    return E_BAD_TYPE;
  940. }
  941.  
  942.  
  943. /***************************************************************/
  944. /*                                                             */
  945. /*  GreaterThan, LessThan, EqualTo, NotEqual, LessOrEqual,     */
  946. /*  GreaterOrEqual                                             */
  947. /*                                                             */
  948. /*  All the comparison functions.                              */
  949. /*                                                             */
  950. /***************************************************************/
  951. #ifdef HAVE_PROTOS
  952. PRIVATE int GreaterThan(void) {return Compare(GT);}
  953. PRIVATE int LessThan(void) {return Compare(LT);}
  954. PRIVATE int EqualTo(void) {return Compare(EQ);}
  955. PRIVATE int NotEqual(void) {return Compare(NE);}
  956. PRIVATE int LessOrEqual(void) {return Compare(LE);}
  957. PRIVATE int GreaterOrEqual(void) {return Compare(GE);}
  958. #else
  959. static int GreaterThan() {return Compare(GT);}
  960. static int LessThan() {return Compare(LT);}
  961. static int EqualTo() {return Compare(EQ);}
  962. static int NotEqual() {return Compare(NE);}
  963. static int LessOrEqual() {return Compare(LE);}
  964. static int GreaterOrEqual() {return Compare(GE);}
  965. #endif
  966.  
  967. /***************************************************************/
  968. /*                                                             */
  969. /*  Compare                                                    */
  970. /*  Do the actual work of comparison.                          */
  971. /*                                                             */
  972. /***************************************************************/
  973. #ifdef HAVE_PROTOS
  974. PRIVATE int Compare(int how)
  975. #else
  976. static int Compare(how)
  977. int how;
  978. #endif
  979. {
  980.    Value v1, v2, v3;
  981.    int r;
  982.  
  983.    if (r = PopValStack(&v2)) return r;
  984.    if (r = PopValStack(&v1)) {
  985.       DestroyValue(&v2);
  986.       return r;
  987.    }
  988.  
  989. /* Special case for EQ and NE */
  990.  
  991.    v3.type = INT_TYPE;
  992.    if (v1.type != v2.type) {
  993.       DestroyValue(&v1); DestroyValue(&v2);
  994.       if (how == EQ) {
  995.          v3.v.val = 0;
  996.      return PushValStack(&v3);
  997.       } else if (how == NE) {
  998.          v3.v.val = 1;
  999.      return PushValStack(&v3);
  1000.       } else return E_BAD_TYPE;
  1001.    }
  1002.  
  1003.    if (v1.type == STR_TYPE) {
  1004.       switch(how) {
  1005.          case EQ: v3.v.val = (strcmp(v1.v.str, v2.v.str) == 0); break;
  1006.          case NE: v3.v.val = (strcmp(v1.v.str, v2.v.str) != 0); break;
  1007.          case LT: v3.v.val = (strcmp(v1.v.str, v2.v.str) < 0); break;
  1008.          case GT: v3.v.val = (strcmp(v1.v.str, v2.v.str) > 0); break;
  1009.          case LE: v3.v.val = (strcmp(v1.v.str, v2.v.str) <= 0); break;
  1010.          case GE: v3.v.val = (strcmp(v1.v.str, v2.v.str) >= 0); break;
  1011.       }
  1012.    } else {
  1013.       switch(how) {
  1014.          case EQ: v3.v.val = (v1.v.val == v2.v.val); break;
  1015.          case NE: v3.v.val = (v1.v.val != v2.v.val); break;
  1016.          case LT: v3.v.val = (v1.v.val < v2.v.val); break;
  1017.          case GT: v3.v.val = (v1.v.val > v2.v.val); break;
  1018.          case LE: v3.v.val = (v1.v.val <= v2.v.val); break;
  1019.          case GE: v3.v.val = (v1.v.val >= v2.v.val); break;
  1020.       }
  1021.    }
  1022.    DestroyValue(&v1); DestroyValue(&v2);
  1023.    return PushValStack(&v3);
  1024. }
  1025.  
  1026. /***************************************************************/
  1027. /*                                                             */
  1028. /*  LogOR                                                      */
  1029. /*                                                             */
  1030. /*  Do logical OR                                              */
  1031. /*                                                             */
  1032. /***************************************************************/
  1033. #ifdef HAVE_PROTOS
  1034. PRIVATE int LogOR(void)
  1035. #else
  1036. static int LogOR()
  1037. #endif
  1038. {
  1039.    Value v1, v2;
  1040.    int r;
  1041.  
  1042.    if (r = PopValStack(&v2)) return r;
  1043.    if (r = PopValStack(&v1)) {
  1044.       DestroyValue(&v2);
  1045.       return r;
  1046.    }
  1047.  
  1048.    if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
  1049.       v1.v.val = (v1.v.val || v2.v.val) ? 1 : 0;
  1050.       return PushValStack(&v1);
  1051.    }
  1052.    DestroyValue(&v1); DestroyValue(&v2);
  1053.    return E_BAD_TYPE;
  1054. }
  1055.  
  1056. /***************************************************************/
  1057. /*                                                             */
  1058. /*  LogAND                                                     */
  1059. /*                                                             */
  1060. /*  Do logical AND                                             */
  1061. /*                                                             */
  1062. /***************************************************************/
  1063. #ifdef HAVE_PROTOS
  1064. PRIVATE int LogAND(void)
  1065. #else
  1066. static int LogAND()
  1067. #endif
  1068. {
  1069.    Value v1, v2;
  1070.    int r;
  1071.  
  1072.    if (r = PopValStack(&v2)) return r;
  1073.    if (r = PopValStack(&v1)) {
  1074.       DestroyValue(&v2);
  1075.       return r;
  1076.    }
  1077.  
  1078.    if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
  1079.       v1.v.val = (v1.v.val && v2.v.val) ? 1 : 0;
  1080.       return PushValStack(&v1);
  1081.    }
  1082.    DestroyValue(&v1); DestroyValue(&v2);
  1083.    return E_BAD_TYPE;
  1084. }
  1085.  
  1086. /***************************************************************/
  1087. /*                                                             */
  1088. /*  UnMinus                                                    */
  1089. /*                                                             */
  1090. /*  Unary Minus                                                */
  1091. /*                                                             */
  1092. /***************************************************************/
  1093. #ifdef HAVE_PROTOS
  1094. PRIVATE int UnMinus(void)
  1095. #else
  1096. static int UnMinus()
  1097. #endif
  1098. {
  1099.    Value *v = &ValStack[ValStackPtr-1];
  1100.    if (v->type != INT_TYPE) return E_BAD_TYPE;
  1101.    v->v.val = -v->v.val;
  1102.    return OK;
  1103. }
  1104.  
  1105. /***************************************************************/
  1106. /*                                                             */
  1107. /*  LogNot                                                     */
  1108. /*                                                             */
  1109. /*  Logical NOT                                                */
  1110. /*                                                             */
  1111. /***************************************************************/
  1112. #ifdef HAVE_PROTOS
  1113. PRIVATE int LogNot(void)
  1114. #else
  1115. static int LogNot()
  1116. #endif
  1117. {
  1118.    Value *v = &ValStack[ValStackPtr-1];
  1119.    if (v->type != INT_TYPE) return E_BAD_TYPE;
  1120.    if (v->v.val) v->v.val = 0; else v->v.val = 1;
  1121.    return OK;
  1122. }
  1123.  
  1124. /***************************************************************/
  1125. /*                                                             */
  1126. /*  FindFunc                                                   */
  1127. /*                                                             */
  1128. /*  Find a function.                                           */
  1129. /*                                                             */
  1130. /***************************************************************/
  1131. #ifdef HAVE_PROTOS
  1132. PRIVATE Operator *FindFunc(char *name, Operator where[], int num)
  1133. #else
  1134. static Operator *FindFunc(name, where, num)
  1135. char *name;
  1136. Operator where[];
  1137. int num;
  1138. #endif
  1139. {
  1140.    int top=num-1, bot=0;
  1141.    int mid, r;
  1142.    while (top >= bot) {
  1143.       mid = (top + bot) / 2;
  1144.       r = StrCmpi(name, where[mid].name);
  1145.       if (!r) return &where[mid];
  1146.       else if (r > 0) bot = mid+1;
  1147.       else top = mid-1;
  1148.    }
  1149.    return NULL;
  1150. }
  1151.     
  1152. /***************************************************************/
  1153. /*                                                             */
  1154. /*  PrintValue                                                 */
  1155. /*                                                             */
  1156. /*  Print a value to stdout for debugging purposes.            */
  1157. /*                                                             */
  1158. /***************************************************************/
  1159. #ifdef HAVE_PROTOS
  1160. PUBLIC void PrintValue (Value *v, FILE *fp)
  1161. #else
  1162. void PrintValue(v, fp)
  1163. Value *v;
  1164. FILE *fp;
  1165. #endif
  1166. {
  1167.    int y, m, d;
  1168.    char *s;
  1169.  
  1170.    if (v->type == STR_TYPE) {
  1171.       s=v->v.str;
  1172.       putc('"', fp);
  1173.       for (y=0; y<MAX_PRT_LEN && *s; y++) putc(*s++, fp);
  1174.       putc('"',fp);
  1175.       if (*s) fprintf(fp, "...");
  1176.    }      
  1177.    else if (v->type == INT_TYPE) fprintf(fp, "%d", v->v.val);
  1178.    else if (v->type == TIM_TYPE) fprintf(fp, "%02d:%02d", v->v.val / 60, v->v.val % 60);
  1179.    else if (v->type == DATE_TYPE) {
  1180.       FromJulian(v->v.val, &y, &m, &d);
  1181.       fprintf(fp, "%04d/%02d/%02d", y, m+1, d);
  1182.    }
  1183.    else fprintf(fp, "ERR");
  1184. }
  1185.  
  1186. /***************************************************************/
  1187. /*                                                             */
  1188. /*  CopyValue                                                  */
  1189. /*                                                             */
  1190. /*  Copy a value.                                              */
  1191. /*                                                             */
  1192. /***************************************************************/
  1193. #ifdef HAVE_PROTOS
  1194. PUBLIC int CopyValue(Value *dest, const Value *src)
  1195. #else
  1196. int CopyValue(dest, src)
  1197. Value *dest, *src;
  1198. #endif
  1199. {
  1200.    dest->type = src->type;
  1201.    if (src->type == STR_TYPE) {
  1202.       dest->v.str = StrDup(src->v.str);
  1203.       if (!dest->v.str) {
  1204.      dest->type = ERR_TYPE;
  1205.      return E_NO_MEM;
  1206.       }
  1207.       return OK;
  1208.    } else {
  1209.       dest->v.val = src->v.val;
  1210.       return OK;
  1211.    }
  1212. }
  1213.